﻿using System;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Security;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Xml;
using System.Xml.Linq;

namespace SharePointPOBox
{
    /// <summary>Provides common variables, constraints, properties and methods</summary>
    public static class Common
    {
        #region const

        /// <summary>Default Library Url</summary>
        public const string DefaultLibraryURL = "SPPOBLib";

        /// <summary>Page Library Url</summary>
        public const string PageLibraryURL = "PostOffice";

        /// <summary>POBox Management List Url</summary>
        public const string ManageListURL = "Lists/SPPOBManage";

        /// <summary>Id of "DownloadItemContentType"</summary>
        public const string DownloadItemContentTypeId = "0x010035baaff4ff6e407ca7b8f42991f69e3d";

        /// <summary>Id of "VendedUploadTicketContentType"</summary>
        public const string VendedUploadTicketContentTypeId = "0x010032b55198c81842c48b019947c06f29f3";

        #endregion const

        #region properties

        /// <summary>POBox management list instance in root web</summary>
        static public SPList ManageList
        {
            get
            {
                SPList list = null;
                try
                {
                    // get list from root web
                    list = Common.GetListFromRootWeb(ManageListURL, false);
                }
                catch (FileNotFoundException)
                {
                    list = null;
                }
                return list;
            }
        }

        /// <summary>POBox management list instance get by SystemAccount in root web</summary>
        static public SPList ManageListBySystemAccount
        {
            get
            {
                SPList list = null;
                try
                {
                    // get list from root web by SystemAccount
                    list = Common.GetListFromRootWeb(ManageListURL, true);
                }
                catch (FileNotFoundException)
                {
                    list = null;
                }
                return list;
            }
        }

        #endregion properties

        #region methods

        /// <summary>Alias of GetCurrentLangString()</summary>
        /// <param name="ResourceName">resource key name</param>
        /// <returns>resource string</returns>
        static public string CurLngStr(string ResourceName)
        {
            return GetCurrentLangString(ResourceName, "SPPOB");
        }

        /// <summary>Get resource string that correspond to specified key from specified resource file.</summary>
        /// <param name="ResourceName">resource key name</param>
        /// <param name="ResourceFile">resource file name</param>
        /// <returns>resource string</returns>
        static public string GetCurrentLangString(string ResourceName, string ResourceFile)
        {
            return SPUtility.GetLocalizedString("$Resources:" + ResourceName, ResourceFile, (uint)System.Globalization.CultureInfo.CurrentUICulture.LCID);
        }

        /// <summary>Get list of specified url from root web.</summary>
        /// <param name="ListURL">Url of list to get</param>
        /// <param name="IsBySystemAccount">When to get by SystemAccount, specify true</param>
        /// <returns>List instance or null</returns>
        static private SPList GetListFromRootWeb(string ListURL, bool IsBySystemAccount)
        {
            return GetListFromRootWeb(ListURL, IsBySystemAccount, null);
        }
        static private SPList GetListFromRootWeb(string ListURL, bool IsBySystemAccount, SPWeb currentWeb)
        {
            if (string.IsNullOrEmpty(ListURL)) return null;

            SPList list = null;
            SPSite site = (currentWeb != null) ? currentWeb.Site : SPContext.Current.Site;
            SPWeb web = null;

            try
            {
                if (IsBySystemAccount)
                {
                    SPSecurity.RunWithElevatedPrivileges(delegate()
                    {
                        site = new SPSite(site.ID);
                    });
                }

                // root web only
                web = site.RootWeb;

                try
                {
                    list = Common.SafeGetList(web, ListURL);
                }
                catch (FileNotFoundException)
                {
                    list = null;
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                if (web != null && SPContext.Current != null && web != SPContext.Current.Web)
                {
                    web.Dispose();
                }
                if (site != null && SPContext.Current != null && site != SPContext.Current.Site)
                {
                    site.Dispose();
                }
            }

            return list;
        }

        /// <summary>Get library of specified url from root web.</summary>
        /// <param name="ListURL">Url of list to get</param>
        /// <param name="IsBySystemAccount">When to get by SystemAccount, specify true</param>
        /// <returns>Library instance or null</returns>
        static public SPDocumentLibrary GetLibrary(string LibUrl, bool IsBySystemAccount)
        {
            return GetListFromRootWeb(LibUrl, IsBySystemAccount) as SPDocumentLibrary;
        }
        static public SPDocumentLibrary GetLibrary(string LibUrl, bool IsBySystemAccount, SPWeb currentWeb)
        {
            return GetListFromRootWeb(LibUrl, IsBySystemAccount, currentWeb) as SPDocumentLibrary;
        }

        /// <summary>Get list instance from url in specified web</summary>
        /// <param name="web">from web</param>
        /// <param name="ListURL">get list's url</param>
        /// <returns>List instance or null</returns>
        static public SPList SafeGetList(SPWeb web, string ListURL)
        {
            if (string.IsNullOrEmpty(ListURL)) return null;

            foreach (SPList list in web.Lists)
            {
                if (list.RootFolder.Url.ToLower() == ListURL.ToLower())
                {
                    return list;
                }
            }
            return null;
        }

        /// <summary>Get random string of specified length</summary>
        /// <param name="length">string length</param>
        /// <param name="WithSymbol">with symbol</param>
        /// <returns>Random string of specified length</returns>
        static public string GenerateRandomString(int length, bool WithSymbol)
        {
            if (WithSymbol)
            {
                return Membership.GeneratePassword(length, (int)(length / 3));
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                while (sb.Length <= length)
                {
                    sb.Append(Guid.NewGuid().ToString("N"));
                }
                return sb.ToString(0, length);
            }
        }

        /// <summary>Create 'mailto:' string for donwload notice mail</summary>
        /// <param name="manageItem">Item related to donwload file</param>
        /// <returns>'mailto:' string for download notice mail</returns>
        static public string CreateMailToLinkForDownload(SPListItem manageItem)
        {
            StringBuilder sbMailto = new StringBuilder("mailto:");

            // Mailaddress
            sbMailto.Append("@");

            // Subject
            sbMailto.Append("?subject=");
            sbMailto.Append(
                HttpUtility.UrlEncode(
                    SharePointPOBox.Common.CurLngStr("SPPOBMailToLinkSubject")).Replace("+", "%20"));

            // Sender name
            SPWeb web = manageItem.Web;
            string sFrom
                = (new SPFieldUserValue(web, (string)manageItem[manageItem.Fields.GetFieldByInternalName("Author").Id]).User.Name);//[manageItem.Fields.GetFieldByInternalName("Uploader").Id])).User.Name;
            if (string.IsNullOrEmpty(sFrom))
            {
                sFrom = " ??? ";
            }
            if (web != SPContext.Current.Web)
            {
                web.Dispose();
            }

            string fName = (string)manageItem[manageItem.Fields.GetFieldByInternalName("Title").Id];

            // Donload deadline
            DateTime tmDeadLine
                = (DateTime)manageItem[manageItem.Fields.GetFieldByInternalName("DownloadDeadline").Id];

            // Download key
            string sDownloadKey = CreateDownloadURL((string)manageItem[manageItem.Fields.GetFieldByInternalName("DownloadKey").Id]);

            // Body
            sbMailto.Append("&body=");
            sbMailto.Append(
                HttpUtility.UrlEncode(
                    string.Format(SharePointPOBox.Common.CurLngStr("SPPOBMailToLinkBody")
                        , sFrom
                        , fName
                        , tmDeadLine.ToShortDateString()
                        , (string)manageItem[manageItem.Fields.GetFieldByInternalName("Purpose").Id]
                        , (string)manageItem[manageItem.Fields.GetFieldByInternalName("Password").Id]
                        , sDownloadKey)).Replace("+", "%20"));

            return sbMailto.ToString();
        }

        /// <summary>Create 'mailto:' string for upload notice mail</summary>
        /// <param name="manageItem">Item related to upload file</param>
        /// <returns>'mailto:' string for upload notice mail</returns>
        static public string CreateMailToLinkForUpload(SPListItem manageItem)
        {
            StringBuilder sbMailto = new StringBuilder("mailto:");

            // Mailaddress
            sbMailto.Append("@");

            // Subject
            sbMailto.Append("?subject=");
            sbMailto.Append(
                HttpUtility.UrlEncode(
                    SharePointPOBox.Common.CurLngStr("SPPOBMailToLinkSubjectForUpload")).Replace("+", "%20"));

            // Sender name
            SPWeb web = manageItem.Web;
            string sFrom
                = (new SPFieldUserValue(web, (string)manageItem[manageItem.Fields.GetFieldByInternalName("Author").Id]).User.Name);//[manageItem.Fields.GetFieldByInternalName("TicketVendor").Id])).User.Name;
            if (string.IsNullOrEmpty(sFrom))
            {
                sFrom = " ??? ";
            }
            if (web != SPContext.Current.Web)
            {
                web.Dispose();
            }

            string fName = (string)manageItem[manageItem.Fields.GetFieldByInternalName("Title").Id];

            // Upload deadline
            DateTime tmDeadLine
                = (DateTime)manageItem[manageItem.Fields.GetFieldByInternalName("UploadDeadline").Id];

            // Upload key
            string sUploadKey = CreateUploadURL((string)manageItem[manageItem.Fields.GetFieldByInternalName("UploadTicket").Id]);

            // Body
            sbMailto.Append("&body=");
            sbMailto.Append(
                HttpUtility.UrlEncode(
                    string.Format(SharePointPOBox.Common.CurLngStr("SPPOBMailToLinkBodyForUpload")
                        , sFrom
                        , tmDeadLine.ToShortDateString()
                        , (string)manageItem[manageItem.Fields.GetFieldByInternalName("Purpose").Id]
                        , (string)manageItem[manageItem.Fields.GetFieldByInternalName("Password").Id]
                        , sUploadKey)).Replace("+", "%20"));

            return sbMailto.ToString();
        }

        /// <summary>Create url for download file</summary>
        /// <param name="UniqueKey">Key that identifies donwload file</param>
        /// <returns>Url for download file</returns>
        static public string CreateDownloadURL(string UniqueKey)
        {
            StringBuilder sbDownloadURL = new StringBuilder();
            if (SPContext.Current.Web.IsRootWeb)
            {
                sbDownloadURL.Append(SPContext.Current.Web.Url.TrimEnd("/".ToCharArray()));
            }
            else
            {
                using (SPWeb rootweb = SPContext.Current.Site.RootWeb)
                {
                    sbDownloadURL.Append(rootweb.Url.TrimEnd("/".ToCharArray()));
                }
            }

            sbDownloadURL.Append("/PostOffice/Box.aspx?");
            sbDownloadURL.Append("uk=" + UniqueKey);

            return sbDownloadURL.ToString();
        }

        /// <summary>Create url for upload file</summary>
        /// <param name="UniqueKey">Key that identifies upload file</param>
        /// <returns>Url for upload file</returns>
        static public string CreateUploadURL(string UniqueKey)
        {
            StringBuilder sbUploadURL = new StringBuilder();
            if (SPContext.Current.Web.IsRootWeb)
            {
                sbUploadURL.Append(SPContext.Current.Web.Url.TrimEnd("/".ToCharArray()));
            }
            else
            {
                using (SPWeb rootweb = SPContext.Current.Site.RootWeb)
                {
                    sbUploadURL.Append(rootweb.Url.TrimEnd("/".ToCharArray()));
                }
            }

            sbUploadURL.Append("/PostOffice/Post.aspx?");
            sbUploadURL.Append("uk=" + UniqueKey);

            return sbUploadURL.ToString();
        }

        /// <summary>Write custom audit log</summary>
        /// <param name="item"></param>
        static public void WriteAuditLog(SPListItem item)
        {
            try
            {
                // Create audit log data (xml)
                XElement root = null;

                if (item.ContentTypeId.IsChildOf(new SPContentTypeId(DownloadItemContentTypeId)))
                {
                    // DownloadItemCotnentType
                    root = new XElement("DownloadLog");
                    root.Add(new XElement("ManageItemId", item.ID));
                    root.Add(new XElement("FileName", item.Title));
                    root.Add(new XElement("FileUrl", HttpContext.Current.Items["DocumentPath"]));
                    root.Add(new XElement("DownloadLimit", item[item.Fields.GetFieldByInternalName("DownloadLimit").Id]));
                    root.Add(new XElement("RequestUrl", HttpContext.Current.Request.Url.AbsoluteUri));
                    root.Add(new XElement("ClientAddress", HttpContext.Current.Request.UserHostAddress));
                    root.Add(new XElement("ClientUserAgent", HttpContext.Current.Request.UserAgent));
                    root.Add(new XElement("Purpose", item[item.Fields.GetFieldByInternalName("Purpose").Id]));
                }
                else
                {
                    // VendedTicketContentType
                    root = new XElement("UploadLog");
                    root.Add(new XElement("ManageItemId", item.ID));
                    root.Add(new XElement("FileName", item.Title));
                    root.Add(new XElement("FileUrl", HttpContext.Current.Items["DocumentPath"]));
                    root.Add(new XElement("FileSize", HttpContext.Current.Request.Files[0].ContentLength));
                    root.Add(new XElement("RequestUrl", HttpContext.Current.Request.Url.AbsoluteUri));
                    root.Add(new XElement("ClientAddress", HttpContext.Current.Request.UserHostAddress));
                    root.Add(new XElement("ClientUserAgent", HttpContext.Current.Request.UserAgent));
                    root.Add(new XElement("Purpose", item[item.Fields.GetFieldByInternalName("Purpose").Id]));
                }

                // Write audit log
                item.ParentList.Audit.WriteAuditEvent(SPAuditEventType.Custom, "SPPostOfficeBox", root.ToString());
            }
            catch (Exception)
            {
            }
        }

        #endregion methods
    }
}
